﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;
using System.Collections.ObjectModel;
using AdminModule.IndexMarkServiceReference;
using SharedCode;
using AdminModule.UserControls.StructView;
using System.Threading;
using AdminModule.StructEditStratagies;
using AdminModule.CommonClasses;

namespace AdminModule.Views
{
    public partial class StructView : Page
    {
        private int IDTerm;
        StructName structName;
        private StructViewBase structViewBase;
        public StructViewBase StructViewBase { get { return this.structViewBase; } }

        // Делегат, который должен быть вызван при добавлении или замене элемента
        private delegate void CallBackMethodDeledate(DTOBase obj);

        public StructView(StructName structName, int IDTerm)
        {
            InitializeComponent();

            this.IDTerm = IDTerm;
            this.structName = structName;

            StructViewBase.changedElements.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ChangedElements_CollectionChanged);

            Init();
            structViewBase.LoadData();
        }

        void Init()
        {
            switch (structName)
            {
                case StructName.IndexMark:
                    this.structViewBase = this.indexMarkStruct;
                    break;

                case StructName.University:
                    this.structViewBase = this.universityStruct;
                    break;

                case StructName.Gradations:
                    copyToTermButton.Visibility = System.Windows.Visibility.Collapsed;
                    this.structViewBase = this.gradationsStruct;
                    break;

                default:
                    this.structViewBase = new StructViewBase();
                    break;
            }

            this.structViewBase.Init(IDTerm);

            #region Подписываемся на события
            // Подписываемся на событие, чтобы узнать о изменении структуры
            structViewBase.structEditStrategy.ObjectChangedEvent += new StructEditBaseStrategy.ObjectChanged(EditStrategy_ObjectChangedEvent);
            // Подписываемся на событие, чтобы узнать о изменении текущего выделенного элемента в дереве
            structViewBase.CurrentItemChanged += new StructViewBase.CurrentItemChangedHandler(structViewBase_CurrentItemChanged);

            structViewBase.events.SaveStarted += () =>
                {
                    progressBar.Text = "Сохранение изменений...";
                    VisibleControls(false);
                };

            structViewBase.events.CopyStarted += () =>
                {
                    progressBar.Text = "Копирование данных...";
                    VisibleControls(false);
                };

            structViewBase.ViewModel.InitStarted += () =>
                {
                    progressBar.SetDefaultText();
                    VisibleControls(false);
                };

            structViewBase.events.DataLoadStarted += () =>
                {
                    progressBar.SetDefaultText();
                    VisibleControls(false);
                };

            structViewBase.events.DataLoadCompleted += () =>
                {
                    VisibleControls(true);
                };

            // Подписываемся на событие, чтобы узнать о сохранении данных на сервере
            structViewBase.events.SaveCompleted += new EventsContainer.SaveCompletedHandler(SaveCompleted);
            // Подписываемся на событие, чтобы узнать о результате копирования данных
            structViewBase.events.CopyCompleted += new EventsContainer.CopyCompletedHandler(CopyCompleted);

            structViewBase.ViewModel.InitCompleted += () =>
            {
                VisibleControls(true);
            };
            #endregion

            structViewBase.Visibility = Visibility.Visible;
        }

        void structViewBase_CurrentItemChanged(ItemsBuffer old, ItemsBuffer _new)
        {
            UpdateEditButtons();
        }

        void EditStrategy_ObjectChangedEvent(object obj)
        {
            UpdateEditButtons();
        }

        void CopyCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            VisibleControls(true);
            if (e.Error != null)
            {
                ErrorWindow.Show(e.Error);
            }
        }

        void ChangedElements_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            UpdateEditButtons();
        }

        void SaveCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            VisibleControls(true);
            if (e.Error != null)
            {
                ErrorWindow.Show(e.Error);
            }
            else
            {
                structViewBase.LoadData();
            }
        }

        void selectElementWindow_Closed(CallBackMethodDeledate 
            CallBackMethod, object sender, EventArgs e)
        {
            SelectAddTypeWindow selectElementWindow = sender as SelectAddTypeWindow;

            if (selectElementWindow.DialogResult == false) return;

            if (selectElementWindow.GetObject() != null)
            {
                CallBackMethod(selectElementWindow.GetObject());
            }
            if (selectElementWindow.GetObjects().Count() > 0)
            {
                foreach (DTOBase i in selectElementWindow.GetObjects())
                {
                    CallBackMethod(i);
                }
            }

            UpdateEditButtons();
        }

        private void addButton_Click(object sender, RoutedEventArgs e)
        {
            DTOBase tmp = structViewBase.CurrentItem.selectedItem as DTOBase;
            SelectAddTypeWindow f = new SelectAddTypeWindow(tmp, 
                structViewBase.GetTypesList(), ButtonType.Add, true, false);
            f.Closed += (s, ev) => 
            {
                if ((s as SelectAddTypeWindow).DialogResult == false) return;
                selectElementWindow_Closed(structViewBase.Add, s, ev); 
            };
            f.Show();
        }

        private void deleteButton_Click(object sender, RoutedEventArgs e)
        {
            MessageBoxResult r = MessageBox.Show("Удалить элемент?", MyAssemblyInfo.Title, MessageBoxButton.OKCancel);
            if (r == MessageBoxResult.Cancel) return;

            structViewBase.Delete();
            UpdateEditButtons();
        }

        private void cutButton_Click(object sender, RoutedEventArgs e)
        {
            structViewBase.Cut();
            UpdateEditButtons();
        }

        private void pasteButton_Click(object sender, RoutedEventArgs e)
        {
            structViewBase.Paste();
            UpdateEditButtons();
        }

        private void saveButton_Click(object sender, RoutedEventArgs e)
        {
            int count = structViewBase.ValidatorManager.ValidateAll().Count;
            //if (count > 0)
            //{
            //    MessageBox.Show("Некоторые значения введены некорректно", MyAssemblyInfo.Title, MessageBoxButton.OK);
            //    return;
            //}

            MessageBoxResult r = MessageBox.Show("Сохранить?", MyAssemblyInfo.Title, MessageBoxButton.OKCancel);
            if (r == MessageBoxResult.Cancel) return;

            structViewBase.Save();
        }

        /// <summary>
        /// Метод, вызывающий сохранение данных. Может быть вызван из вне
        /// </summary>
        public void Save()
        {
            structViewBase.Save();
        }

        private void UpdateEditButtons()
        {
            if (StructViewBase.changedElements.Count == 0)
            {
                saveButton.IsEnabled = false;
            }
            else
            {
                saveButton.IsEnabled = true;
            }

            if (structViewBase.CurrentItem == null)
            {
                addButton.IsEnabled = false;
                deleteButton.IsEnabled = false;
                cutButton.IsEnabled = false;
                pasteButton.IsEnabled = false;
                replaceButton.IsEnabled = false;
            }
            else
            {
                addButton.IsEnabled = true;
                deleteButton.IsEnabled = true;
                cutButton.IsEnabled = true;
                replaceButton.IsEnabled = true;
                refreshNodeButton.IsEnabled = true;

                if (structViewBase.BufferItem != null)
                {
                    pasteButton.IsEnabled = true;
                }
                else
                {
                    pasteButton.IsEnabled = false;
                }
            }
        }

        private void copyToTermButton_Click(object sender, RoutedEventArgs e)
        {
            if (StructViewBase.changedElements.Count > 0)
            {
                MessageBox.Show("Перед копированием необходимо сохранить все изменения.", MyAssemblyInfo.Title, MessageBoxButton.OK);
                return;
            }

            SelectTermWindow f = new SelectTermWindow(this.IDTerm);
            f.Show();
            f.Closed += (s, ev) =>
                {
                    AdmTerm Term = (s as IAddObjectSelector).GetObject() as AdmTerm;
                    if (Term == null || f.DialogResult == false || Term.IDTerm == this.IDTerm) return;

                    MessageBoxResult r = MessageBox.Show("Данные, относящиеся к выбранному периоду будут затерты. Продолжить?", MyAssemblyInfo.Title, MessageBoxButton.OKCancel);
                    if (r == MessageBoxResult.Cancel)
                    {
                        return;
                    }
                    structViewBase.CopyAll(this.IDTerm, Term.IDTerm);
                };
        }

        private void copySelectedToTermButton_Click(object sender, RoutedEventArgs e)
        {
            if (StructViewBase.changedElements.Count > 0)
            {
                MessageBox.Show("Перед копированием необходимо сохранить все изменения.", MyAssemblyInfo.Title, MessageBoxButton.OK);
                return;
            }

            SelectTermWindow st = new SelectTermWindow(this.IDTerm);
            st.Closed += (s, ev) =>
            {
                AdmTerm Term = (s as IAddObjectSelector).GetObject() as AdmTerm;
                if (Term == null || st.DialogResult == false) return;

                SelectTargetCopyWindow selectToCopyWindow = new SelectTargetCopyWindow(this.structName, Term.IDTerm);
                selectToCopyWindow.Closed += (s2, ev2) =>
                    {
                        DTOBase targetObject = (s2 as IAddObjectSelector).GetObject();
                        if (targetObject == null || selectToCopyWindow.DialogResult == false) return;

                        structViewBase.CopySelected(targetObject, Term.IDTerm);
                    };
                selectToCopyWindow.Show();
            };
            st.Show();
        }

        private void replaceButton_Click(object sender, RoutedEventArgs e)
        {
            DTOBase tmp = structViewBase.CurrentItem.selectedItem as DTOBase;
            SelectAddTypeWindow f = new SelectAddTypeWindow(tmp, structViewBase.GetTypesList(), ButtonType.Replace, false, true);
            f.Closed += (s, ev) => 
            {
                if ((s as SelectAddTypeWindow).DialogResult == false) return;
                selectElementWindow_Closed(structViewBase.Replace, s, ev); 
            };
            f.Show();
        }

        private void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            MessageBoxResult r = MessageBox.Show("Отменить изменения?", MyAssemblyInfo.Title, MessageBoxButton.OKCancel);
            if (r == MessageBoxResult.OK)
            {
                StructViewBase.changedElements.Clear();
            }
        }

        private void VisibleControls(bool isVisibility)
        {
            UpdateEditButtons();
            progressBar.IsVisibility = (isVisibility == true) ? Visibility.Collapsed : Visibility.Visible;
            buttonsPanel.Visibility = (isVisibility == true) ? Visibility.Visible : Visibility.Collapsed;
        }

        private void refreshNodeButton_Click(object sender, RoutedEventArgs e)
        {
            structViewBase.RaiseLoadOnDemand();
        }
    }
}
